package com.algorithm.dima.dap;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;
/**
 * Pareto local search algorithm for solving TSP
 * @author heaven
 */
import com.problem.dima.DAPProblem;
import com.util.random.RandomGenerator;
import com.util.solution.impl.DAPSolution;
import com.util.solution.inter.KDNode;

public class ParetoLocalSearch {
	private DAPProblem problem;
	private int run_num;
	public ParetoLocalSearch(DAPProblem problem, int run_num){
		this.problem = problem;
		this.run_num = run_num;
	}
	public void execute(int iteration){
		long startMili=System.currentTimeMillis();
		Iterator<KDNode<DAPSolution>> iter = problem.kdSet.getKDNodes().iterator();		
		while(iter.hasNext()){
			KDNode<DAPSolution> t = iter.next();
			try {
				this.problem.kdStartingSet.add(t.solution.clone());
			} catch (CloneNotSupportedException e) {
				e.printStackTrace();
			}
		}
		while(true){
			int remain = this.problem.kdStartingSet.getPopSize();
			if(remain==0) break;
			this.PLSexecute();
			problem.kdSet.clearAndReset();
		}
		long endMili=System.currentTimeMillis();
		System.out.println("Run of "+this.run_num+":"+(endMili-startMili)/1000+" s ");
		problem.kdSet.saveObjectiveResults("files/results/dima/dap/pls/"+this.problem.devNum+"-"+this.problem.obj_num+".txt");
	}
	public void PLSexecute(){
		int size = problem.kdStartingSet.getPopSize();
		if(size==0) return;
		Random rand = new Random();
		int index = rand.nextInt(size);
		KDNode<DAPSolution> s = problem.kdStartingSet.getKDNodes().get(index);
		this.generateNeigborhood(s.solution);
		s.isDominated = true;
		this.problem.kdStartingSet.clearAndReset();
	}
	public void generateNeigborhood(DAPSolution node){
	    int [] seq = new int[this.problem.devNum*this.problem.posNum];
	    int [] allocated = new int[this.problem.devNum*this.problem.posNum];
	    int [] curObjVal = new int[this.problem.obj_num];
	    int choseNum = 2;//chose two positions
	    int loop = 2;//the number of loops
	    ArrayList<Integer> oneSet = new ArrayList<Integer>();
	    for(int i=0;i<this.problem.posNum*this.problem.devNum;i++)
	        if(node.sequence[i]==1) oneSet.add(i);
	    int len = oneSet.size();
	    for(int iter=0;iter<loop;iter++){
	        int  [] randNum = RandomGenerator.permutation_array(0,len-1);
	        for(int i=0;i<len-choseNum;i+=2){
	        	seq	= node.sequence.clone();
	        	allocated = node.allocated.clone();
	        	curObjVal = node.object_val.clone();
	            int index1 = oneSet.get(randNum[i]);
	            int index2 = oneSet.get(randNum[i+1]);
	            seq[index1] = 0;
	            seq[index2] = 0;
	            curObjVal[0] -= this.problem.MassMatrix[index1];
	            curObjVal[0] -= this.problem.MassMatrix[index2];
	            curObjVal[1] -= this.problem.OICMatrix[index1];
	            curObjVal[1] -= this.problem.OICMatrix[index2];
	            int devIndex1 = index1 % this.problem.devNum;
	            int devIndex2 = index2 % this.problem.devNum;
	            int posIndex1 = index1 / this.problem.devNum;
	            int posIndex2 = index2 / this.problem.devNum;
	            this.problem.releaseRSC(allocated,devIndex1,posIndex1);
	            this.problem.releaseRSC(allocated,devIndex2,posIndex2);
	            for(int j = 0;j < this.problem.posNum;j ++){
	                for(int k = 0;k < this.problem.posNum;k ++){
	                    if(j==k && this.problem.segArray[devIndex1*this.problem.devNum+devIndex2]==1) continue;
	                    if(!this.problem.judgeRsc(allocated, devIndex1, j)
	                    && !this.problem.judgeSeg(seq, j*this.problem.devNum, devIndex1)
	                    && !this.problem.judgeRsc(allocated, devIndex2, k)
	                    && !this.problem.judgeSeg(seq, k*this.problem.devNum,devIndex2)){
	                        int [] tempObjVal = new int[2];
	                        tempObjVal[0] = curObjVal[0]+this.problem.MassMatrix[j*this.problem.devNum+devIndex1];
	                        tempObjVal[0] += this.problem.MassMatrix[k*this.problem.devNum+devIndex2];
	                        tempObjVal[1] = curObjVal[1]+this.problem.OICMatrix[j*this.problem.devNum+devIndex1];
	                        tempObjVal[1] += this.problem.OICMatrix[k*this.problem.devNum+devIndex2];
	                        if(tempObjVal[0]>=node.object_val[0] && tempObjVal[1]>=node.object_val[1])
	                            continue;
	                        DAPSolution newNode = new DAPSolution(this.problem.obj_num, -1);
	                        newNode.sequence = seq.clone();
	                        newNode.sequence[j*this.problem.devNum+devIndex1]=1;
	                        newNode.sequence[k*this.problem.devNum+devIndex2]=1;
	                        newNode.object_val = tempObjVal.clone();
	                        newNode.allocated = allocated.clone();
	                        for(int m=0;m<this.problem.rscNum;m++){
	                            newNode.allocated[m*this.problem.posNum+j]+=this.problem.devRscArray[m*this.problem.devNum+devIndex1];
	                            newNode.allocated[m*this.problem.posNum+k]+=this.problem.devRscArray[m*this.problem.devNum+devIndex2];
	                        }
	                        if(problem.kdSet.add(newNode)){
	                        	problem.kdStartingSet.add(newNode);
	        				}
	                    }
	                }
	            }
	        }
	    }
	}
	public static void main(String []args){
		DAPProblem dap = new DAPProblem();
		new ParetoLocalSearch(dap, 1).execute(600);
	}
}
